package com.ai.service.impl;

import com.ai.domain.pojo.Chat;
import com.ai.domain.vo.ChatVo;
import com.ai.domain.vo.HistoryVo;
import com.ai.handler.RedisChatMemoryHandler;
import com.ai.mapper.ChatMapper;
import com.ai.service.AIService;
import com.ai.service.IChatService;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.common.context.UserContextHolder;
import com.common.exception.ai.AIException;
import com.common.handler.RedisKeysHandler;
import jakarta.annotation.Resource;
import org.springframework.ai.chat.client.ChatClient;
import org.springframework.ai.chat.memory.ChatMemory;
import org.springframework.ai.chat.messages.AssistantMessage;
import org.springframework.ai.chat.messages.Message;
import org.springframework.ai.chat.messages.MessageType;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import reactor.core.publisher.Flux;

import java.util.Collections;
import java.util.List;
import java.util.Map;

/**
 * <p>
 * 对话列表 服务实现类
 * </p>
 *
 * @author 小杰大人
 * @since 2025-05-08
 */
@Service
public class ChatServiceImpl extends ServiceImpl<ChatMapper, Chat> implements IChatService {

    @Resource
    ChatClient openAiChatClient;

    @Resource(type = RedisChatMemoryHandler.class)
    ChatMemory chatMemory;

    @Resource
    StringRedisTemplate stringRedisTemplate;

    private static final Long CHAT_MEMORY_CONVERSATION_SIZE_MAX = 100L;

    @Override
    public List<ChatVo> historyList() {
        Long usersId = UserContextHolder.getContext().getUsersId();
        List<Chat> list = this.list(new LambdaQueryWrapper<Chat>().eq(Chat::getUserId, usersId).orderByDesc(Chat::getUpdateTime));
        if (list == null || list.isEmpty()) {
            return Collections.emptyList();
        }
         return list.stream().map(
                 chat -> {
                    ChatVo chatVo = new ChatVo();
                    chatVo.setName(chat.getName());
                    chatVo.setType(chat.getType());
                    chatVo.setChatId(chat.getId());
                    return chatVo;
                }
        ).toList();
    }

    /**
     ** @param chatId 会话id
     * @return
     */
    @Override
    public List<HistoryVo> querySelectByConversationId(String chatId) {
        List<Message> messageList = chatMemory.get(chatId);
        return messageList.stream()
                .filter(message -> message.getMessageType() == MessageType.USER || message.getMessageType() == MessageType.ASSISTANT)
                .map(message -> {
            HistoryVo historyVo = new HistoryVo();
            historyVo.setRole(message.getMessageType().getValue());
            historyVo.setContent(message.getText());
            return historyVo;
        }).toList();
    }

    @Override
    public Flux<String> stream(String type, String prompt, Long chatId) {
        if (checkConversation(chatId)){
            return Flux.just(AIException.AI_CONVERSATION_OUTPUT_LIMIT);
        }
        return openAiChatClient.prompt()
                .user(prompt)
                .advisors(advisorSpec -> {
                    // 将会话id添加到 AdvisorContext上下文中
                    advisorSpec.param(ChatMemory.CONVERSATION_ID, chatId);
                }).toolContext(Map.of(
                        AUTHENTICATION_TOKEN,UserContextHolder.getContext().getUsersToken(),	// 额外提供用户认证token
                        USER_ID,UserContextHolder.getContext().getUsersId()))	// 用户id
                .stream()
                .content()
                .concatWith(Flux.just(CHAT_MEMORY_END));// 明确结束标识
    }

    @Override
    @Transactional
    public void addChat() {
        Chat chat = new Chat();
        chat.setType("chat");
        chat.setName("新对话" + System.currentTimeMillis());
        chat.setUserId(UserContextHolder.getContext().getUsersId());
        boolean save = this.save(chat);
        if (save){
            chatMemory.add(String.valueOf(chat.getId()), new AssistantMessage(AIService.DEFAULT_AI_ASSISTANT));
        }

    }

    @Override
    @Transactional
    public void deleteChatById(Long id) {
        boolean remove = this.removeById(id);
        if (remove){
            // 删除会话下的所有消息
            chatMemory.clear(id.toString());
        }

    }

    @Override
    @Transactional
    public void updateChat(Chat chat) {
        this.updateById(chat);
    }

    private boolean checkConversation(Long conversationId) {
        Long size = stringRedisTemplate.opsForList().size(RedisKeysHandler.getAiHistoryKey(conversationId.toString()));
        return size != null && size >= (CHAT_MEMORY_CONVERSATION_SIZE_MAX << 1) + 1;
    }
}
